package info.niwota.pasta;

import info.niwota.pasta.net.Callback;
import info.niwota.pasta.net.Client;
import info.niwota.pasta.net.Server;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class NoteHelper {

	private static final String TAG = "NoteHelper";
	private Activity mContext;

	@SuppressWarnings("unused")
	private NoteHelper() {
	}

	public NoteHelper(Activity context) {
		mContext = context;
	}

	public void doLoad() {
		int cnt = 0;
		InputStreamReader fr = null;
		ArrayList<StringBuffer[]> records = new ArrayList<StringBuffer[]>();
		try {
			fr = new InputStreamReader(mContext.getResources().openRawResource(
					R.raw.notes));

			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			factory.setNamespaceAware(false);
			XmlPullParser xpp = factory.newPullParser();
			xpp.setInput(fr);
			int eventType = xpp.getEventType();
			StringBuffer[] cur = new StringBuffer[5];
			int curIdx = -1;
			while (eventType != XmlPullParser.END_DOCUMENT) {
				// save the previous note data-holder when we end a <note> tag
				if (eventType == XmlPullParser.END_TAG
						&& "note".equals(xpp.getName())) {
					if (cur[0] != null && cur[1] != null && !"".equals(cur[0])
							&& !"".equals(cur[1])) {
						records.add(cur);
					}
					cur = new StringBuffer[5];
					curIdx = -1;
				} else if (eventType == XmlPullParser.START_TAG
						&& "title".equals(xpp.getName())) {
					curIdx = 0;
				} else if (eventType == XmlPullParser.START_TAG
						&& "body".equals(xpp.getName())) {
					curIdx = 1;
				} else if (eventType == XmlPullParser.START_TAG
						&& "attachment".equals(xpp.getName())) {
					curIdx = 2;
				} else if (eventType == XmlPullParser.START_TAG
						&& "created".equals(xpp.getName())) {
					curIdx = 3;
				} else if (eventType == XmlPullParser.START_TAG
						&& "modified".equals(xpp.getName())) {
					curIdx = 4;
				} else if (eventType == XmlPullParser.TEXT && curIdx > -1) {
					if (cur[curIdx] == null) {
						cur[curIdx] = new StringBuffer();
					}
					cur[curIdx].append(xpp.getText());
				}
				eventType = xpp.next();
			}

			// we stored data in a stringbuffer so we can skip empty records;
			// now process the successful records & save to Provider
			Long now = System.currentTimeMillis();
			for (StringBuffer[] record : records) {
				Uri uri = Uri.withAppendedPath(Note.Notes.ALL_NOTES_URI,
						record[0].toString());
				ContentValues values = new ContentValues();
				values.put("title", record[0].toString().trim());
				values.put("body", record[1].toString().trim());
				values.put("attachment", record[2].toString().trim());
				values.put("created", parseLong(record[3].toString().trim(),
						now));
				values.put("modified", parseLong(record[4].toString().trim(),
						now));
				if (mContext.getContentResolver().insert(uri, values) != null) {
					cnt++;
				}
			}
		} catch (XmlPullParserException e) {
			showResult(R.string.import_failure_title, mContext.getResources()
					.getString(R.string.import_failure_corrupt, e.getMessage()));
			return;
		} catch (Exception e) {
			showResult(R.string.import_failure_title, mContext.getResources()
					.getString(R.string.import_failure_error, e.getMessage()));
			return;
		} finally {
			if (fr != null) {
				try {
					fr.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private int exportData(StringBuffer sb) {
		Cursor c = mContext.managedQuery(Note.Notes.ALL_NOTES_URI,
				Note.NOTE_EXPORT_PROJECTION, null, null,
				Note.Notes.DEFAULT_SORT_ORDER);

		boolean dataAvailable = c.moveToFirst();
		String title, body, attachment, created, modified;
		int cnt = 0;
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<notes>");
		while (dataAvailable) {
			title = c.getString(c.getColumnIndexOrThrow("title"));
			body = c.getString(c.getColumnIndexOrThrow("body"));
			attachment = c.getString(c.getColumnIndexOrThrow("attachment"));
			modified = c.getString(c.getColumnIndexOrThrow("modified"));
			created = c.getString(c.getColumnIndexOrThrow("created"));
			//
			if (!"".equals(title) && title != null) {
				sb.append("\n");
				sb.append("<note>\n\t<title><![CDATA[");
				sb.append(title);
				sb.append("]]></title>\n\t<body><![CDATA[");
				sb.append(body);
				sb.append("]]></body>\n\t<attachment><![CDATA[");
				sb.append(attachment);
				sb.append("]]></attachment>\n\t<created>");
				sb.append(created);
				sb.append("</created>\n\t");
				sb.append("<modified>");
				sb.append(modified);
				sb.append("</modified>\n</note>");
				cnt++;
			}
			dataAvailable = c.moveToNext();
		}
		sb.append("\n</notes>\n");
		
		return cnt;
	}
	
//	public void exportNotes() {
//		StringBuffer sb = new StringBuffer();
//		int cnt = exportData(sb);
//		//
//		copyToClipboard(sb.toString());
//		//
//		showResult(R.string.export_success_title, String.format(mContext
//				.getResources().getString(R.string.export_success), cnt));
//	}
	
	public void doExport() {
		final String title = "Export to:";
		LayoutInflater factory = LayoutInflater.from(mContext);
		final View view = factory.inflate(R.layout.export_net,
				null);
		AlertDialog d = new AlertDialog.Builder(mContext)
				.setTitle(title)
				.setView(view)
				.setPositiveButton(R.string.button_ok,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
								try {
									final StringBuffer sb = new StringBuffer();
									final int cnt = exportData(sb);
									
									EditText h = (EditText) view.findViewById(R.id.export_host);
									EditText p = (EditText) view.findViewById(R.id.export_port);
									
									final String host = h.getText().toString();
									final int port = Integer.parseInt(p.getText().toString());
									
									//quick and dirty
									AlertDialog a = (AlertDialog) dialog;
									a.setTitle(R.string.text_please_wait);
									//
									Client.send(host, port, sb.toString());
									
									showResult(R.string.export_success_title, String.format(mContext
											.getResources().getString(R.string.export_success), cnt));
								} catch (Exception e) {
									showError(e);
								}
							}
						})
				.setNegativeButton(R.string.button_cancel,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
							}
						}).create();
		d.show();
	}

	private void showError(final Exception e) {
		Toast.makeText(mContext, e.getMessage()+"", Toast.LENGTH_SHORT).show();
	}
	
	private void showErrorBG(final Exception e) {
		mContext.runOnUiThread(new Runnable() {
            public void run() {
            	Toast.makeText(mContext, e.getMessage()+"", Toast.LENGTH_SHORT).show();
            }
        });
	}
	
	private Long parseLong(String s, Long val) {
		try {
			return Long.parseLong(s);
		} catch (Exception e) {
		}
		return val;
	}
	
	public void doImport() throws Exception {
		final AlertDialog[] d = new AlertDialog[1];
		final Server serv = new Server(new Callback() {
			public void handle(String data) {
				try {
					importData(data, true);
					
					if (d[0] != null) {
						d[0].dismiss();
					}
				} catch (Exception e) {
					e.printStackTrace();
					
					showErrorBG(e);
				}
			}
		});
		
		final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog,
					int which) {
				serv.cancel();
			}
		};
		
		
		serv.start();
		//
		final String title = "Import ready at:";
		final String msg = "Host: " + serv.getAddress() + " Port: " + serv.getPort();
		d[0] = new AlertDialog.Builder(mContext).setCancelable(true).setTitle(title).setMessage(msg)
				.setNegativeButton(R.string.button_cancel, listener).create();
		d[0].show();
	}

	private void showResult(int titleId, String msg) {
		new AlertDialog.Builder(mContext).setCancelable(false).setTitle(
				mContext.getResources().getString(titleId)).setMessage(msg)
				.setPositiveButton(R.string.button_ok,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
							}
						}).create().show();
	}
	
	private void showResultBG(final int titleId, final String msg) {
		mContext.runOnUiThread(new Runnable() {
            public void run() {
            	new AlertDialog.Builder(mContext).setCancelable(false).setTitle(
        				mContext.getResources().getString(titleId)).setMessage(msg)
        				.setPositiveButton(R.string.button_ok,
        						new DialogInterface.OnClickListener() {
        							public void onClick(DialogInterface dialog,
        									int which) {
        							}
        						}).create().show();
            }
        });
	}

//	private void copyToClipboard(String s) {
//		ClipboardManager cb = (ClipboardManager) mContext
//				.getSystemService(Context.CLIPBOARD_SERVICE);
//		cb.setText(s);
//	}

//	public boolean canImport() {
//		ClipboardManager cb = (ClipboardManager) mContext
//				.getSystemService(Context.CLIPBOARD_SERVICE);
//		boolean has = cb.hasText();
//		if (!has) {
//			return false;
//		}
//		String txt = cb.getText().toString();
//		// a quick & dirty check
//		return (txt.indexOf("<notes>") > 0 && txt.lastIndexOf("</notes>") > 0);
//	}

//	public void doImport() {
//		// get data from clipboard
//		ClipboardManager cb = (ClipboardManager) mContext
//				.getSystemService(Context.CLIPBOARD_SERVICE);
//		boolean has = cb.hasText();
//		if (!has) {
//			return;
//		}
//		
//		String txt = cb.getText().toString();
//		importData(txt);
//	}
	
	private void importData(String txt, boolean bg) {
		if (Debug.DEBUG) {
			Log.d(TAG, "importData: " + txt);
		}
		StringReader fr = new StringReader(txt);
		int cnt = 0;
		ArrayList<StringBuffer[]> records = new ArrayList<StringBuffer[]>();
		try {
			// next, parse that sucker
			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			factory.setNamespaceAware(false);
			XmlPullParser xpp = factory.newPullParser();
			xpp.setInput(fr);
			int eventType = xpp.getEventType();
			StringBuffer[] cur = new StringBuffer[5];
			int curIdx = -1;
			while (eventType != XmlPullParser.END_DOCUMENT) {
				// save the previous note data-holder when we end a <note> tag
				if (eventType == XmlPullParser.END_TAG
						&& "note".equals(xpp.getName())) {
					if (cur[0] != null && cur[1] != null && !"".equals(cur[0])
							&& !"".equals(cur[1])) {
						records.add(cur);
					}
					cur = new StringBuffer[5];
					curIdx = -1;
				} else if (eventType == XmlPullParser.START_TAG
						&& "title".equals(xpp.getName())) {
					curIdx = 0;
				} else if (eventType == XmlPullParser.START_TAG
						&& "body".equals(xpp.getName())) {
					curIdx = 1;
				} else if (eventType == XmlPullParser.START_TAG
						&& "attachment".equals(xpp.getName())) {
					curIdx = 2;
				} else if (eventType == XmlPullParser.START_TAG
						&& "created".equals(xpp.getName())) {
					curIdx = 3;
				} else if (eventType == XmlPullParser.START_TAG
						&& "modified".equals(xpp.getName())) {
					curIdx = 4;
				} else if (eventType == XmlPullParser.TEXT && curIdx > -1) {
					if (cur[curIdx] == null) {
						cur[curIdx] = new StringBuffer();
					}
					cur[curIdx].append(xpp.getText());
				}
				eventType = xpp.next();
			}

			//
			for (StringBuffer[] record : records) {
				Uri uri = Uri.withAppendedPath(Note.Notes.ALL_NOTES_URI,
						record[0].toString());
				ContentValues values = new ContentValues();
				values.put("title", record[0].toString().trim());
				values.put("body", record[1].toString().trim());
				values.put("attachment", record[2].toString().trim());
				values.put("created", Long.parseLong(record[3].toString()
						.trim()));
				values.put("modified", Long.parseLong(record[4].toString()
						.trim()));
				if (mContext.getContentResolver().insert(uri, values) != null) {
					cnt++;
				}
			}
		} catch (XmlPullParserException e) {
			showResultBG(R.string.import_failure_title, mContext.getResources()
					.getString(R.string.import_failure_corrupt, e.getMessage()));
			return;
		} catch (IOException e) {
			showResultBG(R.string.import_failure_title, mContext.getResources()
					.getString(R.string.import_failure_error, e.getMessage()));
			
			e.printStackTrace();
			return;
		} finally {
			if (fr != null) {
				try {
					fr.close();
				} catch (Exception e) {
				}
			}
		}
		//
		showResultBG(R.string.import_success_title, String.format(mContext
				.getResources().getString(R.string.import_success), cnt));

	}

	public void deleteAll() {
		mContext.getContentResolver().delete(Note.Notes.ALL_NOTES_URI, null, null);
	}
}
